﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;

namespace DTO
{
    public enum EditStatus
    {
        New,
        Edited,
        Saved,
    }

    public class ImageInfo
    {
        #region Attributes
        string _path;
        Bitmap _image;

        public Bitmap Image
        {
            get { return _image; }
            set
            {
                _image = value;
                //_buffData = null;
                //if (_image != null)
                //{
                //    _buffData = new Color[_image.Width, _image.Height];
                //    for (int i = 0; i < _image.Width; i++)
                //        for (int j = 0; j < _image.Height; j++)
                //        {
                //            _buffData[i, j] = _image.GetPixel(i, j);
                //        }
                //}
            }
        }
        Color[,] _buffData;

        public Color[,] BuffData
        {
            get { return _buffData; }
        }


        Bitmap _imageScalBuff;

        public Bitmap ImageScalBuff
        {
            get { return _imageScalBuff; }
        }
        float _scaleRatio = 1;
        public Bitmap CacheScaleImage(float ratio)
        {
            if (Math.Abs(_scaleRatio - ratio) < 0.000001f)
            {
                return ImageScalBuff;
            }
            _scaleRatio = ratio;
            _imageScalBuff = new Bitmap((int)(_image.Width * ratio), (int)(_image.Height * ratio));
            for (int i = 0; i < _imageScalBuff.Width; i++)
            {
                for (int j = 0; j < _imageScalBuff.Height; j++)
                {
                    _imageScalBuff.SetPixel(i, j, _buffData[(int)(i / ratio), (int)(j / ratio)]);

                }
            }
            return _imageScalBuff;
        }

        int _transp;
        ImageAttributes _imageAttr;

        public ImageAttributes ImageAttr
        {
            get { return _imageAttr; }
            set { _imageAttr = value; }
        }
        #endregion
        #region Properties
        public string Path
        {
            get { return _path; }
            set { _path = value; }
        }

        public int Transp
        {
            get { return _transp; }
            set { _transp = value; }
        }
        #endregion
        #region Contructor
        public ImageInfo()
        {
            Path = "";
            _image = null;
            Transp = 0;
            ImageAttr = new ImageAttributes();
            ImageAttr.SetColorKey(Color.White, Color.White);
        }
        #endregion
    }

    public class Module
    {
        #region Attributes
        int _id;

        public int Id
        {
            get { return _id; }
            set { _id = value; }
        }

        int _bmp_Id;

        public int Bmp_Id
        {
            get { return _bmp_Id; }
            set { _bmp_Id = value; }
        }

        int _tmpFlag;

        public int TmpFlag
        {
            get { return _tmpFlag; }
            set { _tmpFlag = value; }
        }

        EditStatus _status;

        public EditStatus Status
        {
            get { return _status; }
            set { _status = value; }
        }

        int _x;

        public int X
        {
            get { return _x; }
            set { _x = value; }
        }
        int _y;

        public int Y
        {
            get { return _y; }
            set { _y = value; }
        }
        int _w;

        public int W
        {
            get { return _w; }
            set { _w = value; }
        }
        int _h;

        public int H
        {
            get { return _h; }
            set { _h = value; }
        }
        string _desc;

        public string Desc
        {
            get { return _desc; }
            set { _desc = value; }
        }
        #endregion

        #region Properties
        public int NumPixels
        {
            get { return W * H; }
        }
        #endregion

        #region Contructor
        public Module()
        {
            Id = -1;
            Status = EditStatus.New;
            X = 0;
            Y = 0;
            W = 20;
            H = 20;
            Desc = "";
        }

        public Module Clone()
        {
            Module clone = new Module();
            clone.Id = this.Id;
            clone.Status = this.Status;
            clone.X = this.X;
            clone.Y = this.Y;
            clone.W = this.W;
            clone.H = this.H;
            clone.Desc = this.Desc;
            return clone;
        }
        #endregion
    }

    public class FModule
    {
        #region Attributes
        EditStatus _status;

        public EditStatus Status
        {
            get { return _status; }
            set { _status = value; }
        }
        int _mid;

        public int Mid
        {
            get { return _mid; }
            set { _mid = value; }
        }
        Module _module;

        public Module Module
        {
            get { return _module; }
            set { _module = value; }
        }
        int _ox;

        public int Ox
        {
            get { return _ox; }
            set { _ox = value; }
        }
        int _oy;

        public int Oy
        {
            get { return _oy; }
            set { _oy = value; }
        }
        float _scaleX;

        public float ScaleX
        {
            get { return _scaleX; }
            set { _scaleX = value; }
        }
        float _scaleY;

        public float ScaleY
        {
            get { return _scaleY; }
            set { _scaleY = value; }
        }
        int _flag;

        byte _alpha;

        public byte Alpha
        {
            get { return _alpha; }
            set { _alpha = value; }
        }

        public int Flag
        {
            get { return _flag; }
            set { _flag = value; }
        }
        #endregion

        #region Properties
        #endregion

        #region Contructor
        public FModule()
        {
            Status = EditStatus.New;
            Mid = -1;
            Ox = 0;
            Oy = 0;
            Alpha = 255;
            Flag = 0;
        }
        public FModule(FModule other)
        {
            Status = other.Status;
            Mid = other.Mid;
            Ox = other.Ox;
            Oy = other.Oy;
            Flag = other.Flag;
        }

        #endregion
    }
    public class Frame
    {
        #region Attributes
        int _id;

        public int Id
        {
            get { return _id; }
            set { _id = value; }
        }
        EditStatus _status;

        public EditStatus Status
        {
            get { return _status; }
            set { _status = value; }
        }
        string _desc;

        public string Desc
        {
            get { return _desc; }
            set { _desc = value; }
        }
        List<FModule> _FModules = new List<FModule>();

        public List<FModule> FModules
        {
            get { return _FModules; }
            set { _FModules = value; }
        }
        #endregion

        #region Properties
        #endregion

        #region Contructor
        public Frame()
        {
            Id = -1;
            Status = EditStatus.New;
            Desc = "";
        }

        public Frame(Frame other)
        {
            Status = other.Status;
            Id = -1;
            Desc = other.Desc;
            for (int i = 0; i < other.FModules.Count; i++)
            {
                FModules.Add(new FModule(other.FModules[i]));
            }
        }

        public Frame Clone()
        {
            Frame clone = new Frame(this);
            clone.Id = this.Id;
            return clone;
        }
        #endregion

        #region Method

        #endregion
    }

    public class AFrame
    {
        #region Attributes
        EditStatus _status;

        public EditStatus Status
        {
            get { return _status; }
            set { _status = value; }
        }
        int _fid;

        public int Fid
        {
            get { return _fid; }
            set { _fid = value; }
        }
        Frame _frame;

        public Frame Frame
        {
            get { return _frame; }
            set { _frame = value; }
        }
        int _time;

        public int Time
        {
            get { return _time; }
            set { _time = value; }
        }
        int _ox;

        public int Ox
        {
            get { return _ox; }
            set { _ox = value; }
        }
        int _oy;

        public int Oy
        {
            get { return _oy; }
            set { _oy = value; }
        }
        int _flag;

        public int Flag
        {
            get { return _flag; }
            set { _flag = value; }
        }
        #endregion

        #region Properties
        #endregion

        #region Contructor
        public AFrame()
        {
            Status = EditStatus.New;
            Fid = -1;
            Time = 1;
            Ox = 0;
            Oy = 0;
            Flag = 0;
        }
        public AFrame(AFrame other)
        {
            Status = other.Status;
            Fid = other.Fid;
            Time = other.Time;
            Ox = other.Ox;
            Oy = other.Oy;
            Flag = other.Flag;
        }
        #endregion
    }
    public class Animation
    {
        #region Attributes
        EditStatus _status;

        public EditStatus Status
        {
            get { return _status; }
            set { _status = value; }
        }
        int _id;

        public int Id
        {
            get { return _id; }
            set { _id = value; }
        }
        string _desc;

        public string Desc
        {
            get { return _desc; }
            set { _desc = value; }
        }
        List<AFrame> _AFrames = new List<AFrame>();

        public List<AFrame> AFrames
        {
            get { return _AFrames; }
            set { _AFrames = value; }
        }

        int _curFrame;

        public int CurFrame
        {
            get { return _curFrame; }
            set { _curFrame = value; }
        }

        int _curTime;

        public int CurTime
        {
            get { return _curTime; }
            set { _curTime = value; }
        }
        #endregion

        #region Properties
        #endregion

        #region Contructor
        public Animation()
        {
            Status = EditStatus.New;
            Id = -1;
            Desc = "";
            CurFrame = -1;
            CurTime = 0;
        }
        public Animation(Animation other)
        {
            Status = other.Status;
            Id = -1;
            Desc = other.Desc;
            for (int i = 0; i < other.AFrames.Count; i++)
            {
                AFrames.Add(new AFrame(other.AFrames[i]));
            }
            CurFrame = -1;
            CurTime = 0;
        }
        public Animation Clone()
        {
            Animation clone = new Animation(this);
            clone.Id = this.Id;
            clone.CurFrame = this.CurFrame;
            clone.CurTime = this.CurTime;
            return clone;
        }
        #endregion

        #region method
        public void UpdateAnimation()
        {
            if (AFrames.Count == 0)
                return;
            if (CurFrame < 0 || CurFrame >= AFrames.Count)
                CurFrame = 0;
            if (CurFrame >= AFrames.Count)
                CurFrame = 0;
            if (CurTime >= AFrames[CurFrame].Time)
            {
                CurFrame = (CurFrame + 1) % AFrames.Count;
                CurTime = 0;
            }
            CurTime++;
        }
        #endregion
    }
    public class SpriteDTO
    {
        public const int FLIP_X = 0x01;
        public const int FLIP_Y = 0x02;
        public const int ROTATE_90 = 0x04;
        public const int ROTATE_180 = 0x08;
        public const int ROTATE_270 = 0x0C;
        #region Attributes
        string _filePath;

        public string FilePath
        {
            get { return _filePath; }
            set { _filePath = value; }
        }
        List<ImageInfo> _imageInfo;


        List<Module> _modules;

        List<Frame> _frames;

        List<Animation> _animations;

        #endregion

        #region Properties
        public List<ImageInfo> ImageInfo
        {
            get { return _imageInfo; }
            set { _imageInfo = value; }
        }
        public List<Module> Modules
        {
            get { return _modules; }
            set { _modules = value; }
        }
        public List<Frame> Frames
        {
            get { return _frames; }
            set { _frames = value; }
        }
        public List<Animation> Animations
        {
            get { return _animations; }
            set { _animations = value; }
        }
        #endregion

        #region Contructor
        public SpriteDTO()
        {
            FilePath = "";
            ImageInfo = new List<ImageInfo>();
            //ImageInfo.Add(new ImageInfo());
            Modules = new List<Module>();
            Frames = new List<Frame>();
            Animations = new List<Animation>();
        }
        #endregion

        #region Method
        public int GetPadX(Frame frame)
        {
            if (frame.FModules.Count == 0)
                return 0;
            int minX = frame.FModules[0].Ox;
            for (int i = 1; i < frame.FModules.Count; i++)
            {
                if (minX > frame.FModules[i].Ox)
                {
                    minX = frame.FModules[i].Ox;
                }
            }

            return -minX;
        }
        public int GetPadY(Frame frame)
        {
            if (frame.FModules.Count == 0)
                return 0;
            int minY = frame.FModules[0].Oy;
            for (int i = 1; i < frame.FModules.Count; i++)
            {
                if (minY > frame.FModules[i].Oy)
                {
                    minY = frame.FModules[i].Oy;
                }
            }

            return -minY;
        }
        public int GetFrameWidth(Frame frame)
        {
            if (frame.FModules.Count == 0)
                return 0;
            Module module;

            module = GetModule(frame.FModules[0].Mid);
            if (module == null)
                return 0;
            int minX = frame.FModules[0].Ox;
            int maxX = minX + module.W;
            for (int i = 1; i < frame.FModules.Count; i++)
            {
                module = GetModule(frame.FModules[i].Mid);
                if (module == null)
                    return 0;
                int tmpMinX = frame.FModules[i].Ox;
                if (minX > tmpMinX)
                {
                    minX = tmpMinX;
                }
                if (maxX < tmpMinX + module.W)
                {
                    maxX = tmpMinX + module.W;
                }
            }
            return maxX - minX;
        }
        public int GetFrameHeight(Frame frame)
        {
            if (frame.FModules.Count == 0)
                return 0;
            Module module;

            module = GetModule(frame.FModules[0].Mid);
            if (module == null)
                return 0;
            int minY = frame.FModules[0].Oy;
            int maxY = minY + module.H;
            for (int i = 1; i < frame.FModules.Count; i++)
            {
                module = GetModule(frame.FModules[i].Mid);
                if (module == null)
                    return 0;
                int tmpMinY = frame.FModules[i].Oy;
                if (minY > tmpMinY)
                {
                    minY = tmpMinY;
                }
                if (maxY < tmpMinY + module.H)
                {
                    maxY = tmpMinY + module.H;
                }
            }
            return maxY - minY;
        }
        public Module GetModule(int id)
        {
            for (int i = 0; i < Modules.Count; i++)
            {
                if (Modules[i].Id == id)
                    return Modules[i];
            }
            return null;
        }
        public Frame GetFrame(int id)
        {
            for (int i = 0; i < Frames.Count; i++)
            {
                if (Frames[i].Id == id)
                    return Frames[i];
            }
            return null;
        }
        public void PaintModule(Graphics g, Module module, int ox, int oy, int flag)
        {
            if (ImageInfo.Count <= 0)
                return;
            Image image = ImageInfo[0].Image;
            if (image == null)
                return;
            int posX = ox;
            int posY = oy;

            //posX += module.X;
            //posY += module.Y;
            Rectangle srcRec = new Rectangle(module.X, module.Y, module.W, module.H);
            Rectangle desRec = new Rectangle((posX), (posY), (module.W), (module.H));
            if ((flag & 0x01) != 0)
            {
                desRec.X += desRec.Width;
                desRec.Width = -desRec.Width;
            }
            if ((flag & 0x02) != 0)
            {
                desRec.Y += desRec.Height;
                desRec.Height = -desRec.Height;
            }
            g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.Low;
            g.DrawImage(image, desRec, module.X, module.Y, module.W, module.H, GraphicsUnit.Pixel, ImageInfo[0].ImageAttr);

        }
        public void PaintModule(Graphics g, Module module, int posX, int posY, int ox, int oy, float scale, int flag)
        {
            if (ImageInfo.Count <= 0)
                return;
            Bitmap image = ImageInfo[0].Image;
            if (image == null)
                return;
            //int posX = ox;
            //int posY = oy;

            //posX += module.X;
            //posY += module.Y;
            Rectangle srcRec = new Rectangle(module.X, module.Y, module.W, module.H);
            Rectangle desRec = new Rectangle(posX + (int)(ox * scale), posY + (int)(oy * scale), (int)(module.W * scale), (int)(module.H * scale));
            posX = desRec.X;
            posY = desRec.Y;
            desRec.X = 0;
            desRec.Y = 0;
            if ((flag & 0x01) != 0)
            {
                desRec.X += desRec.Width;
                desRec.Width = -desRec.Width;
            }
            if ((flag & 0x02) != 0)
            {
                desRec.Y += desRec.Height;
                desRec.Height = -desRec.Height;
            }

            float rot = 0;

            if ((flag & SpriteDTO.ROTATE_180) != 0)
            {
                if ((flag & SpriteDTO.ROTATE_90) != 0)
                {
                    rot = 270;
                }
                else
                {
                    rot = 180;
                }
            }
            else
            {
                if ((flag & SpriteDTO.ROTATE_90) != 0)
                {
                    rot = 90;
                }
            }


            g.TranslateTransform(posX, posY);
            g.RotateTransform(rot);

            g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.NearestNeighbor;
            if (scale < 2)
                g.DrawImage(image, desRec, module.X, module.Y, module.W, module.H, GraphicsUnit.Pixel, ImageInfo[0].ImageAttr);
            else
            {
                //Bitmap b = ImageInfo[0].CacheScaleImage(scale);

                //g.DrawImage(b, desRec, (int)(module.X * scale), (int)(module.Y * scale), (int)(module.W * scale), (int)(module.H * scale), GraphicsUnit.Pixel, ImageInfo[0].ImageAttr);

                //g.DrawImageUnscaledAndClippedimage, desRec, module.X, module.Y, module.W, module.H, GraphicsUnit.Pixel, ImageInfo[0].ImageAttr);
                g.DrawImage(image, desRec, srcRec,
                    GraphicsUnit.Pixel);
            }

            g.RotateTransform(-rot);
            g.TranslateTransform(-posX, -posY);

            //g.DrawImage(image, posX, posY, new Rectangle(module.X, module.Y, module.W, module.H),
            //    GraphicsUnit.Pixel);
        }
        public void PaintFModule(Graphics g, FModule fmodule, int posX, int posY, int flags, float scale)
        {
            Module module = GetModule(fmodule.Mid);
            if (module != null)
            {
                int offsetX = 0;
                int offsetY = 0;
                int fm_flags = fmodule.Flag & 0xFF;

                fm_flags = flags ^ fm_flags;

                if ((flags & SpriteDTO.FLIP_X) != 0) offsetX = -(fmodule.Ox + module.W);
                else offsetX = (fmodule.Ox);
                if ((flags & SpriteDTO.FLIP_Y) != 0) offsetY = -(fmodule.Oy + module.H);
                else offsetY = (fmodule.Oy);

                PaintModule(g, module, posX, posY, offsetX, offsetY, scale, fm_flags & 0x0F);
            }
        }
        public void PaintFrame(Graphics g, Frame frame, int posX, int posY, int flag)
        {
            PaintFrame(g, frame, posX, posY, flag, 1);
        }
        public void PaintFrame(Graphics g, Frame frame, int posX, int posY, int flag, float scale)
        {
            if (frame == null)
                return;
            for (int i = 0; i < frame.FModules.Count; i++)
            {
                FModule fmodule = frame.FModules[i];
                PaintFModule(g, fmodule, posX, posY, flag, scale);
            }
        }

        public void PaintAndUpdateAnimation(Graphics g, Animation animation, int posX, int posY)
        {
            PaintAndUpdateAnimation(g, animation, posX, posY, 1);
        }
        public void PaintAndUpdateAnimation(Graphics g, Animation animation, int posX, int posY, float scale)
        {
            if (animation.CurFrame < 0 || animation.CurFrame >= animation.AFrames.Count)
                return;
            AFrame aframe = animation.AFrames[animation.CurFrame];
            PaintFrame(g, GetFrame(aframe.Fid), (int)(aframe.Ox * scale + posX), (int)(aframe.Oy * scale + posY), aframe.Flag, scale);
        }


        #endregion
        private static bool Equal(Color c1, Color c2)
        {
            return c1.R == c2.R &&
                c1.G == c2.G &&
                c1.B == c2.B;
        }
        internal byte[] CacheImageModule(int mid, int iImage)
        {
            Module module = Modules[mid];
            Bitmap image = ImageInfo[iImage].Image;
            byte[] buff = new byte[module.W * module.H * 4];

            int k = 0;
            Color trans = Color.FromArgb(ImageInfo[iImage].Transp);
            for (int j = module.Y; j < module.Y + module.H; j++)
                for (int i = module.X; i < module.X + module.W; i++)
                {
                    Color c = image.GetPixel(i, j);

                    buff[k++] = c.R;
                    buff[k++] = c.G;
                    buff[k++] = c.B;
                    if (Equal(c, trans))
                    {
                        buff[k++] = 0;
                    }
                    else
                    {
                        buff[k++] = c.A;
                    }
                }

            return buff;
        }

        public void Copy(SpriteDTO sprite)
        {
            FilePath = sprite.FilePath;

            //ImageInfo.Clear();
            ImageInfo = sprite.ImageInfo;

            Modules.Clear();
            for (int i = 0; i < sprite.Modules.Count; i++)
            {
                Modules.Add(sprite.Modules[i].Clone());
            }

            Frames.Clear();
            for (int i = 0; i < sprite.Frames.Count; i++)
            {
                Frames.Add(sprite.Frames[i].Clone());
            }

            Animations.Clear();
            for (int i = 0; i < sprite.Animations.Count; i++)
            {
                Animations.Add(sprite.Animations[i].Clone());
            }
        }
    }
    public class ASprite
    {

        /// Default constructor
        public ASprite() { }

        /// Default destructor
        ~ASprite() { }

        /// Initialize sprite with a .bsprite file
        /// 
        Color transColor;
        public bool Load(SpriteDTO spriteDTO)
        {
            transColor = Color.FromArgb(spriteDTO.ImageInfo[0].Transp);
            m_FModules_Count = 0;
            foreach (Frame frame in spriteDTO.Frames)
            {
                m_FModules_Count += (short)frame.FModules.Count;
                for (int i = 0; i < frame.FModules.Count; i++)
                {
                    Module module = spriteDTO.GetModule(frame.FModules[i].Mid);
                    frame.FModules[i].Mid = spriteDTO.Modules.IndexOf(module);
                }
            }
            for (int i = 0; i < spriteDTO.Modules.Count; i++)
            {
                spriteDTO.Modules[i].Id = i;
            }

            m_AFrames_Count = 0;
            foreach (Animation animation in spriteDTO.Animations)
            {
                m_AFrames_Count += (short)animation.AFrames.Count;
                for (int i = 0; i < animation.AFrames.Count; i++)
                {
                    Frame frame = spriteDTO.GetFrame(animation.AFrames[i].Fid);
                    animation.AFrames[i].Fid = spriteDTO.Frames.IndexOf(frame);
                }
            }
            for (int i = 0; i < spriteDTO.Frames.Count; i++)
            {
                spriteDTO.Frames[i].Id = i;
            }

            m_iVersion = 0x100;

            m_Modules_Count = (short)spriteDTO.Modules.Count;
            if (m_Modules_Count > 0)
            {
                m_pModules_X = new short[m_Modules_Count];
                m_pModules_Y = new short[m_Modules_Count];
                m_pModules_W = new short[m_Modules_Count];
                m_pModules_H = new short[m_Modules_Count];
                for (int i = 0; i < m_Modules_Count; i++)
                {
                    m_pModules_X[i] = (short)spriteDTO.Modules[i].X;
                    m_pModules_Y[i] = (short)spriteDTO.Modules[i].Y;
                    m_pModules_W[i] = (short)spriteDTO.Modules[i].W;
                    m_pModules_H[i] = (short)spriteDTO.Modules[i].H;
                }
            }

            if (m_FModules_Count > 0)
            {
                m_pFModules_ID = new short[m_FModules_Count];
                m_pFModules_ScaleX = new float[m_FModules_Count];
                m_pFModules_ScaleY = new float[m_FModules_Count];
                m_pFModules_Ox = new short[m_FModules_Count];
                m_pFModules_Oy = new short[m_FModules_Count];
                m_pFModules_Alpha = new byte[m_FModules_Count];
                m_pFModules_Flag = new byte[m_FModules_Count];
                int k = 0;
                foreach (Frame frame in spriteDTO.Frames)
                {
                    for (int i = 0; i < frame.FModules.Count; i++)
                    {
                        m_pFModules_ID[k] = (short)frame.FModules[i].Mid;
                        m_pFModules_ScaleX[k] = (float)frame.FModules[i].ScaleX;
                        m_pFModules_ScaleY[k] = (float)frame.FModules[i].ScaleY;
                        m_pFModules_Ox[k] = (short)frame.FModules[i].Ox;
                        m_pFModules_Oy[k] = (short)frame.FModules[i].Oy;
                        m_pFModules_Alpha[k] = (byte)frame.FModules[i].Alpha;
                        m_pFModules_Flag[k] = (byte)frame.FModules[i].Flag;
                        k++;
                    }
                }
            }

            m_Frames_Count = (short)spriteDTO.Frames.Count;
            if (m_Frames_Count > 0)
            {
                m_pFrames_FModulesCount = new short[m_Frames_Count];
                m_pFrames_FModulesStart = new short[m_Frames_Count];

                int nFrames4 = m_Frames_Count << 2;
                m_pFrames_RC = new short[nFrames4];
                short fstart = 0;
                for (int i = 0; i < m_Frames_Count; i++)
                {
                    m_pFrames_FModulesCount[i] = (short)spriteDTO.Frames[i].FModules.Count;
                    m_pFrames_FModulesStart[i] = fstart;
                    fstart += m_pFrames_FModulesCount[i];

                    m_pFrames_RC[4 * i] = (short)spriteDTO.GetPadX(spriteDTO.Frames[i]);
                    m_pFrames_RC[4 * i + 1] = (short)spriteDTO.GetPadY(spriteDTO.Frames[i]);
                    m_pFrames_RC[4 * i + 2] = (short)spriteDTO.GetFrameWidth(spriteDTO.Frames[i]);
                    m_pFrames_RC[4 * i + 3] = (short)spriteDTO.GetFrameHeight(spriteDTO.Frames[i]);
                }
            }

            if (m_AFrames_Count > 0)
            {
                m_pAFrames_ID = new short[m_AFrames_Count];
                m_pAFrames_Time = new short[m_AFrames_Count];
                m_pAFrames_Ox = new short[m_AFrames_Count];
                m_pAFrames_Oy = new short[m_AFrames_Count];
                m_pAFrames_Flag = new byte[m_AFrames_Count];
                int k = 0;
                foreach (Animation animation in spriteDTO.Animations)
                {
                    for (int i = 0; i < animation.AFrames.Count; i++)
                    {
                        m_pAFrames_ID[k] = (short)animation.AFrames[i].Fid;
                        m_pAFrames_Time[k] = (short)animation.AFrames[i].Time;
                        m_pAFrames_Ox[k] = (short)animation.AFrames[i].Ox;
                        m_pAFrames_Oy[k] = (short)animation.AFrames[i].Oy;
                        m_pAFrames_Flag[k] = (byte)animation.AFrames[i].Flag;
                        k++;
                    }
                }
            }

            m_Anims_Count = (short)spriteDTO.Animations.Count;
            if (m_Anims_Count > 0)
            {
                m_pAnims_AFramesCount = new short[m_Anims_Count];
                m_pAnims_AFramesStart = new short[m_Anims_Count];
                short astart = 0;
                for (int i = 0; i < m_Anims_Count; i++)
                {
                    m_pAnims_AFramesCount[i] = (short)spriteDTO.Animations[i].AFrames.Count;
                    m_pAnims_AFramesStart[i] = astart;
                    astart += m_pAnims_AFramesCount[i];
                }
            }

            if (m_Modules_Count <= 0)
                return false;

            //m_Palettes_Count = (byte)spriteDTO.ImageInfo.Count;
            //if (m_Palettes_Count > 0)
            //{
            //    m_pModuleImageData = new byte[m_Palettes_Count][][];
            //    for (int i = 0; i < m_Palettes_Count; i++)
            //    {
            //        m_pModuleImageData[i] = new byte[m_Modules_Count][];
            //        for (int j = 0; j < m_Modules_Count; j++)
            //        {
            //            m_pModuleImageData[i][j] = spriteDTO.CacheImageModule(j,i);
            //        }
            //    }
            //}

            return true;
        }

        public bool SaveV1(string filename)
        {
            CFileWriter writer = CFileWriter.Open(filename);
            if (writer == null)
                return false;

            writer.WriteShort(m_Modules_Count);
            writer.Write(m_pModules_X);
            writer.Write(m_pModules_Y);
            writer.Write(m_pModules_W);
            writer.Write(m_pModules_H);

            writer.WriteShort(m_FModules_Count);
            writer.Write(m_pFModules_ID);
            writer.Write(m_pFModules_Ox);
            writer.Write(m_pFModules_Oy);
            //writer.Write(m_pFModules_Flag);

            writer.WriteShort(m_Frames_Count);
            writer.Write(m_pFrames_FModulesCount);
            writer.Write(m_pFrames_FModulesStart);
            //writer.Write(m_pFrames_RC);

            writer.WriteShort(m_AFrames_Count);
            writer.Write(m_pAFrames_ID);
            writer.Write(m_pAFrames_Time);
            writer.Write(m_pAFrames_Ox);
            writer.Write(m_pAFrames_Oy);
            //writer.Write(m_pAFrames_Flag);

            writer.WriteShort(m_Anims_Count);
            writer.Write(m_pAnims_AFramesCount);
            writer.Write(m_pAnims_AFramesStart);


            //writer.WriteShort(m_Palettes_Count);
            //writer.WriteUShort(0x8888);

            //for (int i = 0; i < m_Palettes_Count; i++)
            //{
            //    for (int j = 0; j < m_Modules_Count; j++)
            //    {
            //        writer.WriteInt(m_pModuleImageData[i][j].Length);
            //        writer.Write(m_pModuleImageData[i][j]);
            //    }
            //}

            writer.Release();
            return true;
        }
        public bool Save(string filename)
        {
            CFileWriter writer = CFileWriter.Open(filename);
            if (writer == null)
                return false;
            writer.WriteShort(m_iVersion);

            writer.WriteShort(m_Modules_Count);
            writer.Write(m_pModules_X);
            writer.Write(m_pModules_Y);
            writer.Write(m_pModules_W);
            writer.Write(m_pModules_H);

            writer.WriteShort(m_FModules_Count);
            writer.Write(m_pFModules_ID);
            writer.Write(m_pFModules_Ox);
            writer.Write(m_pFModules_Oy);
            writer.Write(m_pFModules_Flag);

            writer.WriteShort(m_Frames_Count);
            writer.Write(m_pFrames_FModulesCount);
            writer.Write(m_pFrames_FModulesStart);
            writer.Write(m_pFrames_RC);

            writer.WriteShort(m_AFrames_Count);
            writer.Write(m_pAFrames_ID);
            writer.Write(m_pAFrames_Time);
            writer.Write(m_pAFrames_Ox);
            writer.Write(m_pAFrames_Oy);
            writer.Write(m_pAFrames_Flag);

            writer.WriteShort(m_Anims_Count);
            writer.Write(m_pAnims_AFramesCount);
            writer.Write(m_pAnims_AFramesStart);


            writer.WriteShort(m_Palettes_Count);
            writer.WriteUShort(0x8888);

            for (int i = 0; i < m_Palettes_Count; i++)
            {
                for (int j = 0; j < m_Modules_Count; j++)
                {
                    writer.WriteInt(m_pModuleImageData[i][j].Length);
                    writer.Write(m_pModuleImageData[i][j]);
                }
            }

            writer.Release();
            return true;
        }

        public bool SaveShortData(string filename)
        {
            return SaveShortData(filename, null, false);
        }

        public bool SaveShortData(string filename, Bitmap img)
        {
            return SaveShortData(filename, img, false);
        }

        public bool SaveShortData(string filename, Bitmap img, bool bCacheModule)
        {
            CFileWriter writer = CFileWriter.Open(filename);
            if (writer == null)
                return false;

            writer.WriteShort(m_Modules_Count);

            for (int i = 0; i < m_Modules_Count; i++)
            {
                writer.WriteShort((short)m_pModules_X[i]);
                writer.WriteShort((short)m_pModules_Y[i]);
                writer.WriteShort((short)m_pModules_W[i]);
                writer.WriteShort((short)m_pModules_H[i]);
            }


            writer.WriteShort(m_FModules_Count);
            for (int i = 0; i < m_FModules_Count; i++)
            {
                writer.WriteByte((byte)m_pFModules_ID[i]);
                writer.WriteInt((int)(m_pFModules_ScaleX[i] * 256));
                writer.WriteInt((int)(m_pFModules_ScaleY[i] * 256));
                writer.WriteShort((short)m_pFModules_Ox[i]);
                writer.WriteShort((short)m_pFModules_Oy[i]);
                writer.WriteByte((byte)m_pFModules_Alpha[i]);
                writer.WriteByte((byte)m_pFModules_Flag[i]);
            }

            writer.WriteShort(m_Frames_Count);
            for (int i = 0; i < m_Frames_Count; i++)
            {
                writer.WriteByte((byte)m_pFrames_FModulesCount[i]);
                writer.WriteShort((short)m_pFrames_FModulesStart[i]);
            }

            for (int i = 0; i < m_Frames_Count; i++)
            {
                writer.WriteByte((byte)m_pFrames_RC[i * 4 + 0]);
                writer.WriteByte((byte)m_pFrames_RC[i * 4 + 1]);
                writer.WriteByte((byte)m_pFrames_RC[i * 4 + 2]);
                writer.WriteByte((byte)m_pFrames_RC[i * 4 + 3]);
            }

            writer.WriteShort(m_AFrames_Count);
            for (int i = 0; i < m_AFrames_Count; i++)
            {
                writer.WriteByte((byte)m_pAFrames_ID[i]);
                writer.WriteByte((byte)m_pAFrames_Time[i]);
                writer.WriteByte((byte)m_pAFrames_Ox[i]);
                writer.WriteByte((byte)m_pAFrames_Oy[i]);
                writer.WriteByte((byte)m_pAFrames_Flag[i]);
            }

            writer.WriteShort(m_Anims_Count);
            for (int i = 0; i < m_Anims_Count; i++)
            {
                writer.WriteByte((byte)m_pAnims_AFramesCount[i]);
                writer.WriteShort((short)m_pAnims_AFramesStart[i]);
            }
            if (bCacheModule)
            {
                for (int i = 0; i < m_Modules_Count; i++)
                {
                    byte[] buff = new byte[m_pModules_W[i] * m_pModules_H[i] * 4];
                    int k = 0;
                    for (int v = 0; v < m_pModules_H[i]; v++)
                        for (int u = 0; u < m_pModules_W[i]; u++)
                        {
                            Color c = img.GetPixel(m_pModules_X[i] + u, m_pModules_Y[i] + v);
                            buff[k++] = c.R;
                            buff[k++] = c.G;
                            buff[k++] = c.B;
                            if (SpriteDTO.Equals(c, transColor))
                                buff[k++] = 0;
                            else
                                buff[k++] = c.A;
                        }
                    writer.Write(buff);
                }
            }
            writer.Release();

            //save image
            if (img != null)
            {
                writer = CFileWriter.Open(Path.ChangeExtension(filename, "bbm"));

                writer.WriteByte(16);   //RGBA8888
                int a = Math.Max(img.Width, img.Height);
                int kSize = 1;
                while (kSize < a)
                {
                    kSize *= 2;
                }
                writer.WriteShort((short)kSize);
                writer.WriteShort((short)kSize);
                byte[] buff = new byte[kSize * kSize * 4];

                Array.Clear(buff, 0, buff.Length);

                int k = 0;
                for (int j = 0; j < kSize; j++)
                    for (int i = 0; i < kSize; i++)
                    {
                        if (j < img.Height && i < img.Width)
                        {
                            Color c = img.GetPixel(i, j);

                            buff[k++] = c.R;
                            buff[k++] = c.G;
                            buff[k++] = c.B;
                            if (SpriteDTO.Equals(c, transColor))
                            {
                                buff[k++] = 0;
                            }
                            else
                            {
                                buff[k++] = c.A;
                            }
                        }
                        else
                        {
                            buff[k++] = 0;
                            buff[k++] = 0;
                            buff[k++] = 0;
                            buff[k++] = 0;
                        }

                    }

                writer.Write(buff);
                writer.Release();
            }
            return true;
        }

        /// Sprite info
        private short m_iVersion;
        //private int m_iFlags;

        /// Modules info
        private short m_Modules_Count;
        private short[] m_pModules_X;
        private short[] m_pModules_Y;
        private short[] m_pModules_W;
        private short[] m_pModules_H;
        //private sbyte[] m_pModules_Type;
        //private sbyte[] m_pModules_Color;
#if SPRITE_USE_POW2_TEXTURE_SIZE
	short*	m_pModules_TW;
	short*	m_pModules_TH;
#endif

        /// FModules info
        private short m_FModules_Count;
        private short[] m_pFModules_ID;
        private short[] m_pFModules_Ox;
        private short[] m_pFModules_Oy;
        private float[] m_pFModules_ScaleX;
        private float[] m_pFModules_ScaleY;
        private byte[] m_pFModules_Alpha;
        private byte[] m_pFModules_Flag;

        /// Frames info
        private short m_Frames_Count;
        private short[] m_pFrames_FModulesCount;
        private short[] m_pFrames_FModulesStart;

        private short[] m_pFrames_RC;

        /// AFrames info
        private short m_AFrames_Count;
        private short[] m_pAFrames_ID;
        private short[] m_pAFrames_Time;
        private short[] m_pAFrames_Ox;
        private short[] m_pAFrames_Oy;
        private byte[] m_pAFrames_Flag;

        /// Anims info
        private short m_Anims_Count;
        private short[] m_pAnims_AFramesCount;
        private short[] m_pAnims_AFramesStart;

        /// Palettes, alpha
        private short m_Palettes_Count;
        //private byte m_iCrtPal;
        //private bool m_hasAlpha;

#if SPRITE_CACHE_MODULE_TEXTURES
	/// Texture ID
	GLuint** m_pTextureIds;
#else
        /// Image data
        private byte[][][] m_pModuleImageData;
#endif

        /// Rotation angle
        //private float m_angle;
    }
}
